package cn.cxq.learning.e7;

import java.io.*;
import java.util.ArrayList;

public class LeastSquare {

    double C[][], Y[], X[];
    int RL, RM;
    double PC[][], PY[], PA[][];
    int PL, PM, PN;

    public void FormProblem() throws IOException {

        BufferedReader reader = new BufferedReader(new FileReader(new File("src/cn/cxq/learning/e7/test.txt")));

        String line = reader.readLine();

        String[] split = line.split("\t");

        RM = split.length - 2; // 动态获取变量的个数

        ArrayList<double[]> c = new ArrayList<>(); // 使用可变长数组接收任意个数的测试数据
        ArrayList<Double> y = new ArrayList<>();

        while (true) {
            line = reader.readLine();
            if (line == null) {
                break;
            }
            split = line.split("\t");

            c.add(new double[]{1.0, Double.parseDouble(split[1]), Double.parseDouble(split[2])});
            y.add(Double.parseDouble(split[4]));
        }

        RL = c.size();

        C = new double[RL][RM];
        X = new double[RM];
        Y = new double[RL];

        for (int i = 0; i < RL; i++) {
            C[i] = c.get(i);
        }

        for (int i = 0; i < RL; i++) {
            Y[i] = y.get(i);
        }
    }

    private void FormNormalEquation() {
        int i, j, k;
        double temp;
        for (i = 0; i < PM; i++)
            for (j = i; j < PM; j++) {
                temp = 0.0;
                for (k = 0; k < PL; k++) temp += PC[k][i] * PC[k][j];
                PA[i][j] = temp;
                PA[j][i] = temp;
            }
        for (i = 0; i < PM; i++) {
            temp = 0.0;
            for (k = 0; k < PL; k++) temp += PC[k][i] * PY[k];
            PA[i][PM] = temp;
        }
        return;
    }

    private int Jordan() {
        int i, j, k;
        double x;
        for (k = 0; k < PM; k++) {
            x = PA[k][k];
            for (j = k; j < PN; j++) PA[k][j] /= x;
            for (i = 0; i < PM; i++) {
                if (i == k) continue;
                x = PA[i][k];
                for (j = k; j < PN; j++)
                    PA[i][j] -= x * PA[k][j];
            }
        }
        return 0;
    }

    private double Objective(double[] x) {
        int l, m;
        double OBJ = 0.0, temp = 0.0;
        for (l = 0; l < PL; l++) {
            temp = 0.0;
            for (m = 0; m < PM; m++) temp += x[m] * PC[l][m];
            temp -= PY[l];
            OBJ += temp * temp;
        }
        return OBJ;
    }

    public double SolutionCLEG() {
        int k, ErrCode = 0;

        PL = RL;
        PM = RM;
        PN = RM + 1;
        PY = Y;
        PC = C.clone();
        PA = new double[PM][PN];
        FormNormalEquation();
        Jordan();
        for (k = 0; k < PM; k++) X[k] = PA[k][PN - 1];
        return Objective(X);
    }
}
